package com.dycong.common.json;

import com.fasterxml.jackson.databind.ObjectMapper;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import net.sf.json.JsonConfig;
import org.apache.log4j.Logger;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.*;

/**
 * Created by Duke on 2017/2/16.
 */
public class MyJsonUtil {

    static Logger logger = Logger.getLogger(MyJsonUtil.class);

    /**
     * 对象转换成JSON字符串
     *
     * @param obj 需要转换的对象
     * @return 对象的string字符
     */
    public static String objToJson(Object obj) {
        JSONObject jSONObject = JSONObject.fromObject(obj);
        return jSONObject.toString();
    }

    /**
     * 使用 JsonConfig 过虑属性：适用于 JavaBean/Map
     *
     * @param o
     * @param excludes 过虑属性
     * @return
     */
    public static String toJsonString(Object o, String[] excludes) {
        JsonConfig config = new JsonConfig();
        config.setExcludes(excludes);                  // 指定在转换时不包含哪些属性
        JSONObject jsonObject = JSONObject.fromObject(o, config);    // 在转换时传入之前的配置对象
        return jsonObject.toString();
    }

    /**
     * JSON字符串转换成对象
     *
     * @param jsonString 需要转换的字符串
     * @param type       需要转换的对象类型
     * @return 对象
     */
    @SuppressWarnings("unchecked")
    public static <T> T fromJson(String jsonString, Class<T> type) {
        JSONObject jsonObject = JSONObject.fromObject(jsonString);
        return (T) JSONObject.toBean(jsonObject, type);
    }

    /*TODO 当一个JSONArray里的item(JSONObject)包含一个JSONArray时（eg:上例为JSON一个元素时）时对这个里JSONArray需要匹配一个Class,以item名为key,以对应的class为value放入Map传入
     *TODO 对应Object里包含数组或集合(数组或集合对应JSONArray[{},{}]，单个对象Object对应内部json{}),内部JSONArray时需要ClassMap,JSONObject是不需要ClassMap
     *TODO ObjectMapper不需要这么做
     */
    public static <T> T fromJson(String jsonString, Class<T> type, Map<String, Class> map) {
        if (null == map || map.size() == 0) {
            return fromJson(jsonString, type);
        }
        JSONObject jsonObject = JSONObject.fromObject(jsonString);
        return (T) JSONObject.toBean(jsonObject, type, map);
    }

    /**
     * 将JSONArray对象转换成list集合
     *
     * @param jsonArr
     * @return
     */
    public static List<Object> jsonToList(JSONArray jsonArr) {
        List<Object> list = new ArrayList<Object>();
        for (Object obj : jsonArr) {
            if (obj instanceof JSONArray) {
                list.add(jsonToList((JSONArray) obj));
            } else if (obj instanceof JSONObject) {
                list.add(jsonToMap((JSONObject) obj));
            } else {
                list.add(obj);
            }
        }
        return list;
    }

    /**
     * 将json字符串转换成map对象
     *
     * @param json
     * @return
     */
    public static Map<String, Object> jsonToMap(String json) {
        JSONObject obj = JSONObject.fromObject(json);
        return jsonToMap(obj);
    }

    /**
     * 返回值为List<Map>
     *
     * @param json
     * @return
     */
    public static List<Object> jsonToList(String json) {
        JSONArray array = JSONArray.fromObject(json);
        return jsonToList(array);
    }

    /**
     * 将JSONObject转换成map对象
     *
     * @param obj
     * @return
     */
    public static Map<String, Object> jsonToMap(JSONObject obj) {
        Set<?> set = obj.keySet();
        Map<String, Object> map = new HashMap<String, Object>(set.size());
        for (Object key : obj.keySet()) {
            Object value = obj.get(key);
            if (value instanceof JSONArray) {
                map.put(key.toString(), jsonToList((JSONArray) value));
            } else if (value instanceof JSONObject) {
                map.put(key.toString(), jsonToMap((JSONObject) value));
            } else {
                map.put(key.toString(), obj.get(key));
            }
        }
        return map;
    }

    public MyJsonUtil() {
    }

    /**
     * @param json
     * @param clazz
     * @param <T>
     * @return
     * @see TODO jackson ObjectMapper
     * List<LinkedHashMap<String, Object>> list = objectMapper.readValue(json, List.class);
     * @see AccountBean[] arr = objectMapper.readValue(json, AccountBean[].class);不能返回List<AccountBean>但是可以返回AccountBean[]
     * Map<String, Map<String, Object>> maps = objectMapper.readValue(json, Map.class);
     */
    public static <T> T toObject(String json, Class<T> clazz) {
        try {
            ObjectMapper e = new ObjectMapper();
            return e.readValue(json.getBytes("UTF-8"), clazz);
        } catch (IOException | RuntimeException var3) {
            logger.info("parsing json to Object error, json is: " + json);
            logger.debug("", var3);
            return null;
        }
    }

    public static Map<String, Object> toObject(String json) {
        return (Map) toObject(json, HashMap.class);
    }

    /**
     * @param object
     * @return
     */
    public static String toJson(Object object) {
        if (object == null) {
            return null;
        } else if (object instanceof String) {
            return object.toString();
        } else {
            ObjectMapper objectMapper = new ObjectMapper();

            try {
                ByteArrayOutputStream e = new ByteArrayOutputStream();
                Throwable var3 = null;

                String var5;
                try {
                    objectMapper.writeValue(e, object);
                    String json = e.toString("UTF-8");
                    var5 = json;
                } catch (Throwable var15) {
                    var3 = var15;
                    throw var15;
                } finally {
                    if (e != null) {
                        if (var3 != null) {
                            try {
                                e.close();
                            } catch (Throwable var14) {
                                var3.addSuppressed(var14);
                            }
                        } else {
                            e.close();
                        }
                    }

                }

                return var5;
            } catch (RuntimeException | IOException var17) {
                logger.warn("parse json error", var17);
                return null;
            }
        }
    }

    public static Map<String, Object> toMap(String json) {
        return toObject(json, HashMap.class);
    }

    public static <T> T convertValue(Object from, Class<T> to) {
        ObjectMapper objectMapper = new ObjectMapper();
        return objectMapper.convertValue(from, to);
    }
    /*net.sf.json.JSONArray*/

    /**
     * @param jsonObject
     * @param clazz
     * @return
     */
    public Object jsonObjectToObject(JSONObject jsonObject, Class clazz) {
        if (null == jsonObject || null == clazz) {
            return null;
        }
        return JSONObject.toBean(jsonObject, clazz);
    }

    /**
     * @param jsonArray
     * @param o
     * @return
     */
    public Object jsonObjectToObjectList(JSONArray jsonArray, Object o) {
        if (null == jsonArray || null == o) {
            return null;
        }
        return JSONArray.toList(jsonArray, o, new JsonConfig());
    }

    /**
     * @param jsonArray
     * @param clazz
     * @return
     */
    public Object jsonObjectToObjectCollection(JSONArray jsonArray, Class clazz) {
        if (null == jsonArray || null == clazz) {
            return null;
        }
        return JSONArray.toCollection(jsonArray, clazz);
    }

    /**
     * @param jsonArray
     * @param clazz
     * @return
     */
    public Object jsonObjectToObjectArray(JSONArray jsonArray, Class clazz) {
        if (null == jsonArray || null == clazz) {
            return null;
        }
        return JSONArray.toArray(jsonArray, clazz);
    }

    /**
     * "productItems":[{"skuId":"","id":"0001825620"}]
     * TODO 当一个JSONArray里的item(JSONObject)包含一个JSONArray时（eg:上例为JSON一个元素时）时对这个里JSONArray需要匹配一个Class,以item名为key,以对应的class为value放入Map传入
     * TODO 对应Object里包含数组或集合(数组或集合对应JSONArray[{},{}]，单个对象Object对应内部json{}),内部JSONArray时需要ClassMap,JSONObject是不需要ClassMap
     * TODO ObjectMapper不需要这么做
     * @param jsonArray
     * @param clazz
     * @param map
     * @return
     */
    public Object jsonObjectToObjectArray(JSONArray jsonArray, Class clazz, Map<String, Class> map) {
        if (null == jsonArray || null == clazz) {
            return null;
        }
        if (map == null || map.size() == 0) {
            return jsonObjectToObjectArray(jsonArray, clazz);
        }
        return JSONArray.toArray(jsonArray, clazz, map);
    }
}
